Türkçe

TypeScript'in yardımcı tiplerinde ustalaşın: Tip dönüşümleri için güçlü araçlarla kod yeniden kullanılabilirliğini artırın ve uygulamalarınızda tip güvenliğini güçlendirin.

TypeScript Yardımcı Tipleri: Dahili Tip Manipülasyon Araçları

TypeScript, JavaScript'e statik tipleme getiren güçlü bir dildir. Temel özelliklerinden biri, geliştiricilerin daha sağlam ve sürdürülebilir kodlar oluşturmasına olanak tanıyan tipleri manipüle etme yeteneğidir. TypeScript, yaygın tip dönüşümlerini basitleştiren bir dizi dahili yardımcı tip sunar. Bu yardımcı tipler, tip güvenliğini artırmak, kodun yeniden kullanılabilirliğini iyileştirmek ve geliştirme iş akışınızı kolaylaştırmak için paha biçilmez araçlardır. Bu kapsamlı rehber, en temel TypeScript yardımcı tiplerini inceleyerek, bunlarda ustalaşmanıza yardımcı olacak pratik örnekler ve uygulanabilir bilgiler sunar.

TypeScript Yardımcı Tipleri Nedir?

Yardımcı tipler, mevcut tipleri yeni tiplere dönüştüren önceden tanımlanmış tip operatörleridir. TypeScript diline entegre edilmişlerdir ve yaygın tip manipülasyonlarını gerçekleştirmek için öz ve bildirimsel bir yol sağlarlar. Yardımcı tipleri kullanmak, standart kod miktarını önemli ölçüde azaltabilir ve tip tanımlarınızı daha anlamlı ve anlaşılır hale getirebilir.

Bunları, değerler yerine tipler üzerinde çalışan fonksiyonlar olarak düşünebilirsiniz. Girdi olarak bir tip alırlar ve çıktı olarak değiştirilmiş bir tip döndürürler. Bu, minimum kodla karmaşık tip ilişkileri ve dönüşümleri oluşturmanıza olanak tanır.

Neden Yardımcı Tipler Kullanılmalı?

TypeScript projelerinize yardımcı tipleri dahil etmek için birkaç güçlü neden vardır:

Temel TypeScript Yardımcı Tipleri

TypeScript'teki en sık kullanılan ve faydalı yardımcı tiplerden bazılarını inceleyelim. Amaçlarını, sözdizimlerini ele alacak ve kullanımlarını göstermek için pratik örnekler sunacağız.

1. Partial<T>

Partial<T> yardımcı tipi, T tipinin tüm özelliklerini isteğe bağlı hale getirir. Bu, mevcut bir tipin bazı veya tüm özelliklerine sahip yeni bir tip oluşturmak istediğinizde, ancak hepsinin mevcut olmasını zorunlu kılmak istemediğinizde kullanışlıdır.

Sözdizimi:

type Partial<T> = { [P in keyof T]?: T[P]; };

Örnek:

interface User {
 id: number;
 name: string;
 email: string;
}

type OptionalUser = Partial<User>; // Artık tüm özellikler isteğe bağlı

const partialUser: OptionalUser = {
 name: "Alice", // Sadece name özelliği sağlanıyor
};

Kullanım Alanı: Bir nesneyi yalnızca belirli özelliklerle güncellemek. Örneğin, bir kullanıcı profili güncelleme formu düşünün. Kullanıcıların her alanı aynı anda güncellemesini zorunlu kılmak istemezsiniz.

2. Required<T>

Required<T> yardımcı tipi, T tipinin tüm özelliklerini zorunlu hale getirir. Bu, Partial<T>'nin tam tersidir. İsteğe bağlı özelliklere sahip bir tipiniz olduğunda ve tüm özelliklerin mevcut olduğundan emin olmak istediğinizde kullanışlıdır.

Sözdizimi:

type Required<T> = { [P in keyof T]-?: T[P]; };

Örnek:

interface Config {
 apiKey?: string;
 apiUrl?: string;
}

type CompleteConfig = Required<Config>; // Artık tüm özellikler zorunlu

const config: CompleteConfig = {
 apiKey: "your-api-key",
 apiUrl: "https://example.com/api",
};

Kullanım Alanı: Bir uygulamayı başlatmadan önce tüm yapılandırma ayarlarının sağlandığından emin olmak. Bu, eksik veya tanımsız ayarlardan kaynaklanan çalışma zamanı hatalarını önlemeye yardımcı olabilir.

3. Readonly<T>

Readonly<T> yardımcı tipi, T tipinin tüm özelliklerini salt okunur (readonly) yapar. Bu, bir nesne oluşturulduktan sonra özelliklerini yanlışlıkla değiştirmenizi engeller. Bu, değişmezliği (immutability) teşvik eder ve kodunuzun öngörülebilirliğini artırır.

Sözdizimi:

type Readonly<T> = { readonly [P in keyof T]: T[P]; };

Örnek:

interface Product {
 id: number;
 name: string;
 price: number;
}

type ImmutableProduct = Readonly<Product>; // Artık tüm özellikler salt okunur

const product: ImmutableProduct = {
 id: 123,
 name: "Örnek Ürün",
 price: 25.99,
};

// product.price = 29.99; // Hata: 'price' salt okunur bir özellik olduğu için atama yapılamaz.

Kullanım Alanı: Yapılandırma nesneleri veya veri aktarım nesneleri (DTO'lar) gibi oluşturulduktan sonra değiştirilmemesi gereken değişmez (immutable) veri yapıları oluşturmak. Bu, özellikle fonksiyonel programlama paradigmalarında kullanışlıdır.

4. Pick<T, K extends keyof T>

Pick<T, K extends keyof T> yardımcı tipi, T tipinden K özellikler kümesini seçerek yeni bir tip oluşturur. Bu, mevcut bir tipin özelliklerinin yalnızca bir alt kümesine ihtiyaç duyduğunuzda kullanışlıdır.

Sözdizimi:

type Pick<T, K extends keyof T> = { [P in K]: T[P]; };

Örnek:

interface Employee {
 id: number;
 name: string;
 department: string;
 salary: number;
}

type EmployeeNameAndDepartment = Pick<Employee, "name" | "department">; // Sadece name ve department seçilir

const employeeInfo: EmployeeNameAndDepartment = {
 name: "Bob",
 department: "Mühendislik",
};

Kullanım Alanı: Belirli bir işlem için yalnızca gerekli verileri içeren özel veri aktarım nesneleri (DTO'lar) oluşturmak. Bu, performansı artırabilir ve ağ üzerinden iletilen veri miktarını azaltabilir. Müşteriye maaş gibi hassas bilgileri hariç tutarak kullanıcı ayrıntılarını gönderdiğinizi düşünün. Sadece `id` ve `name` göndermek için Pick'i kullanabilirsiniz.

5. Omit<T, K extends keyof any>

Omit<T, K extends keyof any> yardımcı tipi, T tipinden K özellikler kümesini çıkararak yeni bir tip oluşturur. Bu, Pick<T, K extends keyof T>'nin tersidir ve mevcut bir tipten belirli özellikleri hariç tutmak istediğinizde kullanışlıdır.

Sözdizimi:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

Örnek:

interface Event {
 id: number;
 title: string;
 description: string;
 date: Date;
 location: string;
}

type EventSummary = Omit<Event, "description" | "location">; // description ve location hariç tutulur

const eventPreview: EventSummary = {
 id: 1,
 title: "Konferans",
 date: new Date(),
};

Kullanım Alanı: Tam açıklamayı ve konumu dahil etmeden bir etkinliğin özetini görüntülemek gibi belirli amaçlar için veri modellerinin basitleştirilmiş sürümlerini oluşturmak. Bu, verileri bir istemciye göndermeden önce hassas alanları kaldırmak için de kullanılabilir.

6. Exclude<T, U>

Exclude<T, U> yardımcı tipi, T'den U'ya atanabilen tüm tipleri hariç tutarak yeni bir tip oluşturur. Bu, bir birleşim tipinden (union type) belirli tipleri kaldırmak istediğinizde kullanışlıdır.

Sözdizimi:

type Exclude<T, U> = T extends U ? never : T;

Örnek:

type AllowedFileTypes = "image" | "video" | "audio" | "document";
type MediaFileTypes = "image" | "video" | "audio";

type DocumentFileTypes = Exclude<AllowedFileTypes, MediaFileTypes>; // "document"

const fileType: DocumentFileTypes = "document";

Kullanım Alanı: Belirli bir bağlamda ilgili olmayan belirli tipleri kaldırmak için bir birleşim tipini filtrelemek. Örneğin, izin verilen dosya türleri listesinden belirli dosya türlerini hariç tutmak isteyebilirsiniz.

7. Extract<T, U>

Extract<T, U> yardımcı tipi, T'den U'ya atanabilen tüm tipleri çekerek (extracting) yeni bir tip oluşturur. Bu, Exclude<T, U>'nun tersidir ve bir birleşim tipinden belirli tipleri seçmek istediğinizde kullanışlıdır.

Sözdizimi:

type Extract<T, U> = T extends U ? T : never;

Örnek:

type InputTypes = string | number | boolean | null | undefined;
type PrimitiveTypes = string | number | boolean;

type NonNullablePrimitives = Extract<InputTypes, PrimitiveTypes>; // string | number | boolean

const value: NonNullablePrimitives = "hello";

Kullanım Alanı: Belirli ölçütlere göre bir birleşim tipinden belirli tipleri seçmek. Örneğin, hem ilkel tipleri hem de nesne tiplerini içeren bir birleşim tipinden tüm ilkel tipleri çıkarmak isteyebilirsiniz.

8. NonNullable<T>

NonNullable<T> yardımcı tipi, T tipinden null ve undefined'ı hariç tutarak yeni bir tip oluşturur. Bu, bir tipin null veya undefined olamayacağından emin olmak istediğinizde kullanışlıdır.

Sözdizimi:

type NonNullable<T> = T extends null | undefined ? never : T;

Örnek:

type MaybeString = string | null | undefined;

type DefinitelyString = NonNullable<MaybeString>; // string

const message: DefinitelyString = "Merhaba, dünya!";

Kullanım Alanı: Bir değer üzerinde bir işlem yapmadan önce o değerin null veya undefined olmadığından emin olmak. Bu, beklenmedik null veya undefined değerlerinden kaynaklanan çalışma zamanı hatalarını önlemeye yardımcı olabilir. Bir kullanıcının adresini işlemeniz gereken ve herhangi bir işlemden önce adresin null olmamasının çok önemli olduğu bir senaryo düşünün.

9. ReturnType<T extends (...args: any) => any>

ReturnType<T extends (...args: any) => any> yardımcı tipi, bir T fonksiyon tipinin dönüş tipini çıkarır. Bu, bir fonksiyonun döndürdüğü değerin tipini bilmek istediğinizde kullanışlıdır.

Sözdizimi:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

Örnek:

function fetchData(url: string): Promise<{ data: any }> {
 return fetch(url).then(response => response.json());
}

type FetchDataReturnType = ReturnType<typeof fetchData>; // Promise<{ data: any }>

async function processData(data: FetchDataReturnType) {
 // ...
}

Kullanım Alanı: Özellikle asenkron işlemler veya karmaşık fonksiyon imzalarıyla uğraşırken bir fonksiyonun döndürdüğü değerin tipini belirlemek. Bu, döndürülen değeri doğru bir şekilde ele aldığınızdan emin olmanızı sağlar.

10. Parameters<T extends (...args: any) => any>

Parameters<T extends (...args: any) => any> yardımcı tipi, bir T fonksiyon tipinin parametre tiplerini bir demet (tuple) olarak çıkarır. Bu, bir fonksiyonun kabul ettiği argümanların tiplerini bilmek istediğinizde kullanışlıdır.

Sözdizimi:

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

Örnek:

function createUser(name: string, age: number, email: string): void {
 // ...
}

type CreateUserParams = Parameters<typeof createUser>; // [string, number, string]

function logUser(...args: CreateUserParams) {
 console.log("Kullanıcı oluşturuluyor:", args);
}

Kullanım Alanı: Farklı imzalara sahip fonksiyonlarla çalışması gereken jenerik fonksiyonlar veya dekoratörler oluşturmak için faydalı olan, bir fonksiyonun kabul ettiği argümanların tiplerini belirlemek. Bir fonksiyona dinamik olarak argüman geçerken tip güvenliğini sağlamaya yardımcı olur.

11. ConstructorParameters<T extends abstract new (...args: any) => any>

ConstructorParameters<T extends abstract new (...args: any) => any> yardımcı tipi, bir T kurucu fonksiyon (constructor) tipinin parametre tiplerini bir demet (tuple) olarak çıkarır. Bu, bir kurucunun kabul ettiği argümanların tiplerini bilmek istediğinizde kullanışlıdır.

Sözdizimi:

type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;

Örnek:

class Logger {
 constructor(public prefix: string, public enabled: boolean) {}
 log(message: string) {
 if (this.enabled) {
 console.log(`${this.prefix}: ${message}`);
 }
 }
}

type LoggerConstructorParams = ConstructorParameters<typeof Logger>; // [string, boolean]

function createLogger(...args: LoggerConstructorParams) {
 return new Logger(...args);
}

Kullanım Alanı: Parameters'a benzer, ancak özellikle kurucu fonksiyonlar içindir. Farklı kurucu imzalara sahip sınıfları dinamik olarak somutlaştırmanız gereken fabrikalar (factories) veya bağımlılık enjeksiyonu (dependency injection) sistemleri oluştururken yardımcı olur.

12. InstanceType<T extends abstract new (...args: any) => any>

InstanceType<T extends abstract new (...args: any) => any> yardımcı tipi, bir T kurucu fonksiyon (constructor) tipinin örnek (instance) tipini çıkarır. Bu, bir kurucunun oluşturduğu nesnenin tipini bilmek istediğinizde kullanışlıdır.

Sözdizimi:

type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;

Örnek:

class Greeter {
 greeting: string;
 constructor(message: string) {
 this.greeting = message;
 }
 greet() {
 return "Merhaba, " + this.greeting;
 }
}

type GreeterInstance = InstanceType<typeof Greeter>; // Greeter

const myGreeter: GreeterInstance = new Greeter("Dünya");
console.log(myGreeter.greet());

Kullanım Alanı: Kalıtım (inheritance) veya polimorfizm (polymorphism) ile çalışırken faydalı olan, bir kurucu tarafından oluşturulan nesnenin tipini belirlemek. Bir sınıfın örneğine atıfta bulunmak için tip güvenli bir yol sağlar.

13. Record<K extends keyof any, T>

Record<K extends keyof any, T> yardımcı tipi, özellik anahtarları K ve özellik değerleri T olan bir nesne tipi oluşturur. Bu, anahtarları önceden bildiğiniz sözlük benzeri tipler oluşturmak için kullanışlıdır.

Sözdizimi:

type Record<K extends keyof any, T> = { [P in K]: T; };

Örnek:

type CountryCode = "US" | "CA" | "GB" | "DE";

type CurrencyMap = Record<CountryCode, string>; // { US: string; CA: string; GB: string; DE: string; }

const currencies: CurrencyMap = {
 US: "USD",
 CA: "CAD",
 GB: "GBP",
 DE: "EUR",
};

Kullanım Alanı: Sabit bir anahtar kümeniz olduğu ve tüm anahtarların belirli bir türde değerlere sahip olmasını sağlamak istediğiniz sözlük benzeri nesneler oluşturmak. Bu, yapılandırma dosyaları, veri eşlemeleri veya arama tablolarıyla çalışırken yaygındır.

Özel Yardımcı Tipler

TypeScript'in dahili yardımcı tipleri güçlü olsa da, projelerinizdeki özel ihtiyaçları karşılamak için kendi özel yardımcı tiplerinizi de oluşturabilirsiniz. Bu, karmaşık tip dönüşümlerini kapsüllemenize ve bunları kod tabanınızda yeniden kullanmanıza olanak tanır.

Örnek:

// Bir nesnenin belirli bir tipe sahip anahtarlarını almak için bir yardımcı tip
type KeysOfType<T, U> = { [K in keyof T]: T[K] extends U ? K : never }[keyof T];

interface Person {
 name: string;
 age: number;
 address: string;
 phoneNumber: number;
}

type StringKeys = KeysOfType<Person, string>; // "name" | "address"

Yardımcı Tipleri Kullanmak İçin En İyi Uygulamalar

Sonuç

TypeScript yardımcı tipleri, kodunuzun tip güvenliğini, yeniden kullanılabilirliğini ve sürdürülebilirliğini önemli ölçüde artırabilen güçlü araçlardır. Bu yardımcı tiplerde ustalaşarak, daha sağlam ve anlamlı TypeScript uygulamaları yazabilirsiniz. Bu rehber, projelerinize dahil etmenize yardımcı olacak pratik örnekler ve uygulanabilir bilgiler sunarak en temel TypeScript yardımcı tiplerini kapsamıştır.

Bu yardımcı tiplerle denemeler yapmayı ve kendi kodunuzdaki belirli sorunları çözmek için nasıl kullanılabileceklerini keşfetmeyi unutmayın. Onlara daha aşina oldukça, daha temiz, daha sürdürülebilir ve daha tip güvenli TypeScript uygulamaları oluşturmak için onları giderek daha fazla kullandığınızı göreceksiniz. İster web uygulamaları, ister sunucu tarafı uygulamaları veya arada herhangi bir şey geliştiriyor olun, yardımcı tipler geliştirme iş akışınızı ve kodunuzun kalitesini iyileştirmek için değerli bir araç seti sunar. Bu dahili tip manipülasyon araçlarından yararlanarak, TypeScript'in tüm potansiyelini ortaya çıkarabilir ve hem anlamlı hem de sağlam kodlar yazabilirsiniz.